﻿using System.ComponentModel;
using System.Xml;
using Notoric.Model.Elements;

namespace Notoric.Model.Internal
{
    /// <summary>
    /// Helper class that adds the XML attributes that store the size
    /// of a model element to its XML element.
    /// </summary>
    /// <remarks>
    /// The class does not validate property values. This is left to the using class.
    /// </remarks>
    internal class ResizableHelper : IResizableElement, INotifyPropertyChanged
    {
        #region Constructors

        /// <summary>
        /// Creates a new <see cref="ResizableHelper"/> instance.
        /// </summary>
        /// <param name="element">XML element that holds the model element data.</param>
        /// <param name="load">Indicates whether to load the attributes from the element or create and add them.</param>
        private ResizableHelper(XmlElement element, bool load)
        {
            this.element = element;

            if (load)
            {
                heightAttribute = element.Attributes[PackageVocabulary.HeightAttribute];
                widthAttribute = element.Attributes[PackageVocabulary.WidthAttribute];
            }
            else
            {
                heightAttribute = element.OwnerDocument.CreateAttribute(PackageVocabulary.HeightAttribute);
                widthAttribute = element.OwnerDocument.CreateAttribute(PackageVocabulary.WidthAttribute);

                heightAttribute.Value = (0.0).ToString(PackageVocabulary.PackageCulture.NumberFormat);
                widthAttribute.Value = (0.0).ToString(PackageVocabulary.PackageCulture.NumberFormat);

                element.Attributes.Append(heightAttribute);
                element.Attributes.Append(widthAttribute);
            }
        }

        #endregion

        #region IResizable Members

        /// <inheritdoc/>
        public double Height
        {
            get
            {
                return double.Parse(heightAttribute.Value, PackageVocabulary.PackageCulture.NumberFormat);
            }
            set
            {
                heightAttribute.Value = value.ToString(PackageVocabulary.PackageCulture.NumberFormat);

                if (PropertyChanged != null)
                    PropertyChanged(this, new PropertyChangedEventArgs("Height"));
            }
        }

        /// <inheritdoc/>
        public double Width
        {
            get
            {
                return double.Parse(widthAttribute.Value, PackageVocabulary.PackageCulture.NumberFormat);
            }
            set
            {
                widthAttribute.Value = value.ToString(PackageVocabulary.PackageCulture.NumberFormat);

                if (PropertyChanged != null)
                    PropertyChanged(this, new PropertyChangedEventArgs("Width"));
            }
        }

        #endregion

        #region INotifyPropertyChanged Members

        /// <summary>
        /// Occurs when the value of some property has changed.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        #region Public Methods

        /// <summary>
        /// Creates a new <see cref="ResizableHelper"/> that adds the height and width attributes
        /// to the given XML element and binds to them.
        /// </summary>
        /// <param name="element">The decorated XML element.</param>
        /// <returns>
        /// <para>
        /// Type: <see cref="ResizableHelper"/>
        /// </para>
        /// <para>
        /// The created helper class.
        /// </para>
        /// </returns>
        public static ResizableHelper Create(XmlElement element)
        {
            return new ResizableHelper(element, false);
        }

        /// <summary>
        /// Creates a new <see cref="ResizableHelper"/> that loads the left and top attributes
        /// from the given XML element and binds to them.
        /// </summary>
        /// <param name="element">The decorated XML element.</param>
        /// <returns>
        /// <para>
        /// Type: <see cref="ResizableHelper"/>
        /// </para>
        /// <para>
        /// The created helper class.
        /// </para>
        /// </returns>
        public static ResizableHelper Load(XmlElement element)
        {
            return new ResizableHelper(element, true);
        }

        #endregion

        #region Private Fields

        /// <summary>
        /// Holds the decorated XML element.
        /// </summary>
        private XmlElement element;
        /// <summary>
        /// Holds the XML attribute that holds the value of the <see cref="Height"/> property.
        /// </summary>
        private XmlAttribute heightAttribute;
        /// <summary>
        /// Holds the XML attribute that holds the value of the <see cref="Width"/> property.
        /// </summary>
        private XmlAttribute widthAttribute;

        #endregion
    }
}
